package com.szsky.sky.demo;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class AESNoPaddingUtils {

    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/ECB/NoPadding";

    /**
     * 原始的无填充加密（要求输入数据长度必须是16的倍数）
     */
    public static byte[] encryptNoPadding(byte[] data, byte[] key) {
        try {
            if (data.length % 16 != 0) {
                throw new IllegalArgumentException("数据长度必须是16的倍数");
            }

            SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            throw new RuntimeException("AES加密失败", e);
        }
    }

    /**
     * 原始的无填充解密
     */
    public static byte[] decryptNoPadding(byte[] encryptedData, byte[] key) {
        try {
            if (encryptedData.length % 16 != 0) {
                throw new IllegalArgumentException("加密数据长度必须是16的倍数");
            }

            SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            return cipher.doFinal(encryptedData);
        } catch (Exception e) {
            throw new RuntimeException("AES解密失败", e);
        }
    }

    /**
     * 完整的加解密流程（自动处理填充）
     */
    public static String encryptWithAutoPadding(String data, String key) {
        try {
            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);

            // 自动填充到16的倍数
            byte[] paddedData = padData(dataBytes);

            byte[] encrypted = encryptNoPadding(paddedData, keyBytes);
            return Base64.getEncoder().withoutPadding().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }

    public static String decryptWithAutoPadding(String base64Data, String key) {
        try {
            byte[] encryptedData = Base64.getDecoder().decode(base64Data);
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);

            byte[] decrypted = decryptNoPadding(encryptedData, keyBytes);

            // 移除填充
            byte[] unpaddedData = unpadData(decrypted);

            return new String(unpaddedData, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }


    public static String encryptWithAutoPaddingNoBase64(String data, String key) {
        try {
            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);

            // 自动填充到16的倍数
            byte[] paddedData = padData(dataBytes);

            byte[] encrypted = encryptNoPadding(paddedData, keyBytes);
            return new String(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }



    public static String decryptWithAutoPaddingNoBase64(String base64Data, String key) {
        try {
            byte[] encryptedData = base64Data.getBytes(StandardCharsets.UTF_8);
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);

            byte[] decrypted = decryptNoPadding(encryptedData, keyBytes);

            // 移除填充
            byte[] unpaddedData = unpadData(decrypted);

            return new String(unpaddedData, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }

    /**
     * PKCS7填充
     */
    private static byte[] padData(byte[] data) {
        int blockSize = 16;
        int paddingLength = blockSize - (data.length % blockSize);
        byte[] padded = new byte[data.length + paddingLength];
        System.arraycopy(data, 0, padded, 0, data.length);
        for (int i = data.length; i < padded.length; i++) {
            padded[i] = (byte) paddingLength;
        }
        return padded;
    }

    /**
     * PKCS7去除填充
     */
    private static byte[] unpadData(byte[] data) {
        int paddingLength = data[data.length - 1];
        if (paddingLength < 1 || paddingLength > 16) {
            return data;
        }
        byte[] unpadded = new byte[data.length - paddingLength];
        System.arraycopy(data, 0, unpadded, 0, unpadded.length);
        return unpadded;
    }

    /**
     * 加密并Base64编码
     * @param data 待加密字符串
     * @param key 密钥字符串
     * @return Base64编码的加密结果
     */
    public static String encryptToBase64(String data, String key) {
        byte[] encrypted = encrypt(data.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * 解密Base64编码的加密数据
     * @param base64Data Base64编码的加密数据
     * @param key 密钥字符串
     * @return 解密后的原始字符串
     */
    public static String decryptFromBase64(String base64Data, String key) {
        byte[] encryptedData = Base64.getDecoder().decode(base64Data);
        byte[] decrypted = decrypt(encryptedData, key.getBytes(StandardCharsets.UTF_8));
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    /**
     * AES加密
     * @param data 待加密数据
     * @param key 密钥
     * @return 加密后的字节数组
     */
    public static byte[] encrypt(byte[] data, byte[] key) {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            throw new RuntimeException("AES加密失败", e);
        }
    }

    /**
     * AES解密
     * @param encryptedData 加密后的数据
     * @param key 密钥
     * @return 解密后的字节数组
     */
    public static byte[] decrypt(byte[] encryptedData, byte[] key) {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            return cipher.doFinal(encryptedData);
        } catch (Exception e) {
            throw new RuntimeException("AES解密失败", e);
        }
    }

    public static void main(String[] args) {
        String originalText = "密码";
        String key = "!QAZ2wsx@WSX1qaz";

        System.out.println("原始文本: " + originalText);
        System.out.println("密钥: " + key);
        System.out.println("密钥长度: " + key.getBytes(StandardCharsets.UTF_8).length + " 字节");

        // 加密
        String encryptedBase64 = AESNoPaddingUtils.encryptToBase64(originalText, key);
        System.out.println("加密结果(Base64): " + encryptedBase64);

        // 解密
        String decryptedText = AESNoPaddingUtils.decryptFromBase64(encryptedBase64, key);
        System.out.println("解密结果: " + decryptedText);

        // 验证加解密一致性
        System.out.println("加解密是否一致: " + originalText.equals(decryptedText));

        String encryptedBase642 = AESNoPaddingUtils.encryptWithAutoPadding(originalText, key);
        System.out.println("加密结果(Base64)-2: " + encryptedBase642);

        // 解密
        String decryptedText2 = AESNoPaddingUtils.decryptFromBase64(encryptedBase642, key);
        System.out.println("解密结果-2: " + decryptedText2);

    }
}